﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MvvmEx.EventArgs;

namespace MvvmEx.Controls.Calendar
{
    /// <summary>
    /// 按照步骤 1a 或 1b 操作，然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
    ///
    /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 
    /// 元素中: 
    ///
    ///     xmlns:MyNamespace="clr-namespace:MvvmEx.Controls.Calendar"
    ///
    ///
    /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 
    /// 元素中: 
    ///
    ///     xmlns:MyNamespace="clr-namespace:MvvmEx.Controls.Calendar;assembly=MvvmEx.Controls.Calendar"
    ///
    /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用，
    /// 并重新生成以避免编译错误: 
    ///
    ///     在解决方案资源管理器中右击目标项目，然后依次单击
    ///     “添加引用”->“项目”->[浏览查找并选择此项目]
    ///
    ///
    /// 步骤 2)
    /// 继续操作并在 XAML 文件中使用控件。
    ///
    ///     <MyNamespace:MarkerCalendar/>
    ///
    /// </summary>
    public class MarkerCalendar : Control
    {
        #region 字段

        private List<MarkerCalendarItem> _markerCalendarItems;
        private ItemsControl _itemsControl;
        private static readonly Dictionary<DayOfWeek, int> _dayOfWeek = new Dictionary<DayOfWeek, int>()
        {
            {DayOfWeek.Monday, 0},
            {DayOfWeek.Tuesday, 1},
            {DayOfWeek.Wednesday, 2},
            {DayOfWeek.Thursday, 3},
            {DayOfWeek.Friday, 4},
            {DayOfWeek.Saturday, 5},
            {DayOfWeek.Sunday, 6}
        };
        #endregion

        #region 依赖属性

        #region 是否显示确定按钮



        public bool IsShowOkBtn
        {
            get { return (bool)GetValue(IsShowOkBtnProperty); }
            set { SetValue(IsShowOkBtnProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsShowOkBtn.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsShowOkBtnProperty =
            DependencyProperty.Register("IsShowOkBtn", typeof(bool), typeof(MarkerCalendar), new PropertyMetadata(true));



        #endregion


        #region 年
        public int Year
        {
            get
            {
                return (int)GetValue(YearProperty);
            }
            set
            {
                SetValue(YearProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for Year.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty YearProperty =
            DependencyProperty.Register("Year", typeof(int), typeof(MarkerCalendar), new PropertyMetadata(1, PropertyChanged));
        #endregion

        #region 月

        public int Month
        {
            get
            {
                return (int)GetValue(MonthProperty);
            }
            set
            {
                SetValue(MonthProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for Month.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MonthProperty =
            DependencyProperty.Register("Month", typeof(int), typeof(MarkerCalendar), new PropertyMetadata(1, PropertyChanged));

        #endregion

        #region 内容项
        public ObservableCollection<MarkerCalendarDataItem> ItemsSource
        {
            get
            {
                return (ObservableCollection<MarkerCalendarDataItem>)GetValue(ItemsSourceProperty);
            }
            set
            {
                SetValue(ItemsSourceProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for ItemsSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(ObservableCollection<MarkerCalendarDataItem>), typeof(MarkerCalendar), new PropertyMetadata(new ObservableCollection<MarkerCalendarDataItem>(), PropertyChanged));


        #endregion

        #endregion

        #region 事件
        public static readonly RoutedEvent DoubleClickEvent = EventManager.RegisterRoutedEvent("DoubleClick", RoutingStrategy.Bubble,
            typeof(EventHandler<RoutedEventArgs<MarkerCalendarDataItem>>), typeof(MarkerCalendar));

        public event EventHandler<RoutedEventArgs<MarkerCalendarDataItem>> DoubleClick
        {
            add
            {
                this.AddHandler(DoubleClickEvent, value);
            }
            remove
            {
                this.RemoveHandler(DoubleClickEvent, value);
            }
        }

        public static readonly RoutedEvent DeleteEvent = EventManager.RegisterRoutedEvent("Delete",
            RoutingStrategy.Bubble, typeof(EventHandler<RoutedEventArgs<MarkerCalendarDataItem>>), typeof(MarkerCalendar));

        public event EventHandler<RoutedEventArgs<MarkerCalendarDataItem>> Delete
        {
            add
            {
                this.AddHandler(DeleteEvent, value);
            }
            remove { this.RemoveHandler(DeleteEvent, value); }
        }

        #endregion

        #region 构造
        static MarkerCalendar()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MarkerCalendar), new FrameworkPropertyMetadata(typeof(MarkerCalendar)));
        }

        public MarkerCalendar()
        {
            _markerCalendarItems = new List<MarkerCalendarItem>();
        }
        #endregion

        #region 公有方法

        #region 触发事件

        public void OnDoubleClickEvent(MarkerCalendarDataItem e)
        {
            var args = new RoutedEventArgs<MarkerCalendarDataItem>(DoubleClickEvent, this, e);
            this.RaiseEvent(args);
        }

        public void OnDeleteEvent(MarkerCalendarDataItem e)
        {
            var args=new RoutedEventArgs<MarkerCalendarDataItem>(DeleteEvent,this,e);
            this.RaiseEvent(args);
        }

        #endregion

        #endregion

        #region 私有方法

        #region 属性变更事件

        private static void PropertyChanged(object s, DependencyPropertyChangedEventArgs e)
        {
            var obj = s as MarkerCalendar;

            if (obj == null) return;

            obj.Render();
        }

        #endregion

        #region 渲染界面

        private void Render()
        {
            CaculateCalendar();

            Mapping();
        }

        #endregion

        #region 计算日期

        private void CaculateCalendar()
        {
            _markerCalendarItems.Clear();

            //找到这个月有多少天
            var days = DateTime.DaysInMonth(Year, Month);

            for (int i = 1; i <= days; i++)
            {
                _markerCalendarItems.Add(new MarkerCalendarItem(this) { DateTime = new DateTime(Year, Month, i) });
            }

            //找出第一天
            var firstDay = _markerCalendarItems.First().DateTime;

            //找出1号是星期几
            var index = _dayOfWeek[firstDay.DayOfWeek];

            //补齐前面的日期
            for (int i = 1; i <= index; i++)
            {
                var newDate = firstDay.AddDays(-i);
                _markerCalendarItems.Insert(0, new MarkerCalendarItem(this) { DateTime = newDate, });
            }

            //找出最后一天
            var lastDay = _markerCalendarItems.Last().DateTime;

            index = _dayOfWeek[lastDay.DayOfWeek];

            //补齐后面的日期
            for (int i = 1; i < _dayOfWeek.Count - index; i++)
            {
                var newDate = lastDay.AddDays(i);
                _markerCalendarItems.Add(new MarkerCalendarItem(this) { DateTime = newDate, });
            }

            //计算行列
            foreach (var item in _markerCalendarItems)
            {
                var itemIndex = _markerCalendarItems.IndexOf(item);

                var row = itemIndex / _dayOfWeek.Count;
                var column = itemIndex % _dayOfWeek.Count;

                item.Row = row;
                item.Column = column;
            }

            if (_itemsControl != null)
            {
                _itemsControl.Items.Clear();
                _markerCalendarItems.ForEach(x => _itemsControl.Items.Add(x));
            }
        }

        #endregion

        #region 和数据匹配

        private void Mapping()
        {
            if (ItemsSource == null) return;

            foreach (var calendarItem in _markerCalendarItems)
            {
                var item = ItemsSource.FirstOrDefault(
                    x =>
                        x.DateTime.Year == calendarItem.DateTime.Year &&
                        x.DateTime.Month == calendarItem.DateTime.Month &&
                        x.DateTime.Day == calendarItem.Day);

                if (item != null)
                {
                    calendarItem.Content = item.Content;
                    calendarItem.HasValue = true;
                    calendarItem.Id = item.Id;
                }
            }
        }

        #endregion

        #endregion

        #region 重载

        #region 获取部件

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _itemsControl = GetTemplateChild("PART_Items") as ItemsControl;

            if (_itemsControl != null && _markerCalendarItems != null)
            {
                _itemsControl.Items.Clear();
                foreach (var item in _markerCalendarItems)
                {
                    _itemsControl.Items.Add(item);
                }
            }
        }

        #endregion

        #endregion


    }
}
